iT邦幫忙

2026 iThome 鐵人賽

DAY 26
0
Build on Google AI

30 天玩轉 Google AI 全家桶:初學者的隨身 Coding 助理養成記系列 第 26 篇

Day 26:打造本機 CLI:用單行指令呼叫你的 DevPulse

  • 分享至 

  • xImage
  •  

昨天,我們讓 Jest 用同一套測試驗收 samples/ 和 fixed/,確認 Gemini 產生的補丁到底有沒有修好 Bug。

不過目前要操作 DevPulse,還是得先開啟 Genkit 的開發工具,再找到 codeReviewFlow、輸入檔案路徑,最後查看分析結果。功能已經完成,使用流程卻還不夠順手。

今天不重寫 AI 邏輯,而是替現有的 Flow 加上一個命令列入口。完成後,只要在專案目錄輸入:

devpulse run samples/sql.cjs

就能讓 DevPulse 分析指定檔案,並在終端機以不同顏色呈現問題嚴重程度。

今天要完成三件事:

  1. 用 CLI 接收 run 指令與檔案路徑。
  2. 呼叫既有的 codeReviewFlow,不要複製一份 Gemini 分析邏輯。
  3. 用 Chalk 整理終端機輸出,並處理路徑錯誤與分析失敗。

一、CLI 不該重新發明一次 AI 流程

回顧 Day 23,我們已經把程式碼審查封裝成 src/codeReviewFlow.mjs。它接收 { filePath },讀取檔案後呼叫 Gemini,最後回傳固定格式的資料:

  • summary:整體審查摘要。
  • issues:問題清單,包含 line、severity、category、title、explanation 與 suggestion。

因此,CLI 不需要再處理 Prompt、Zod Schema 或 Gemini API。它只要把使用者輸入的路徑交給 codeReviewFlow,再將回傳結果顯示出來即可。

使用者輸入指令
      ↓
CLI 解析 run 與檔案路徑
      ↓
codeReviewFlow
      ↓
Gemini 回傳結構化審查結果
      ↓
CLI 將結果顯示在終端機

這樣分工有個好處:未來想調整 AI 的分析規則,就修改 Flow;想換輸出格式或增加其他指令,則修改 CLI。兩者不必綁在一起。

二、安裝 Chalk,準備 CLI 入口

在 devpulse/ 專案根目錄執行:

npm install chalk@5 dotenv

chalk 用來替終端機文字加上顏色;dotenv 則負責載入專案根目錄的 .env,讓 CLI 啟動時也能讀到 Gemini API Key。

這裡使用 chalk@5,因為專案入口採用 ES Module 的 import 語法。Chalk 5 本身也是 ES Module,能直接搭配使用。

接著建立 bin/devpulse.mjs:

#!/usr/bin/env node

import "dotenv/config";
import path from "node:path";
import chalk from "chalk";
import { codeReviewFlow } from "../src/codeReviewFlow.mjs";

function showHelp() {
  console.log(`
DevPulse - 本機程式碼診斷小幫手

使用方式:
  devpulse run <filePath>  分析指定的程式碼
  devpulse --help          顯示使用說明

範例:
  devpulse run samples/sql.cjs
`);
}

async function main() {
  const [command, targetPath] = process.argv.slice(2);

  if (!command || command === "--help" || command === "help") {
    showHelp();
    return;
  }

  if (command !== "run") {
    console.error(chalk.red(`不支援的指令:${command}`));
    showHelp();
    process.exitCode = 1;
    return;
  }

  if (!targetPath) {
    console.error(chalk.red("請提供要分析的檔案路徑。"));
    showHelp();
    process.exitCode = 1;
    return;
  }

  // 將相對路徑轉成絕對路徑,交給既有的 Flow 讀檔。
  const filePath = path.resolve(process.cwd(), targetPath);

  console.log(chalk.cyan.bold("\nDevPulse 程式碼審查"));
  console.log(chalk.gray(`分析檔案:${filePath}`));

  try {
    const result = await codeReviewFlow({ filePath });

    console.log(`\n${chalk.bold("審查摘要")}`);
    console.log(result.summary);

    if (!result.issues || result.issues.length === 0) {
      console.log(chalk.green("\n✓ 沒有發現問題。"));
      return;
    }

    console.log(chalk.bold(`\n發現 ${result.issues.length} 個問題:`));

    for (const issue of result.issues) {
      const severityLabel = {
        high: chalk.red("HIGH"),
        medium: chalk.yellow("MEDIUM"),
        low: chalk.cyan("LOW"),
      }[issue.severity] ?? chalk.gray(String(issue.severity).toUpperCase());

      console.log(
        `\n${severityLabel} ${chalk.gray(`Line ${issue.line}`)} [${issue.category}] ${issue.title}`,
      );
      console.log(`  原因:${issue.explanation}`);
      console.log(`  建議:${issue.suggestion}`);
    }
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error);
    console.error(chalk.red.bold("\n分析失敗:"), message);
    process.exitCode = 1;
  }
}

main().catch((error) => {
  console.error(chalk.red.bold("CLI 發生未預期錯誤:"), error);
  process.exitCode = 1;
});

這份 CLI 刻意只呼叫 codeReviewFlow,不會直接修改原始檔,也不會擅自把分析結果當成修復成功。補丁套用與 Jest 驗收仍維持前幾天建立的流程,避免一個指令在使用者不知情的情況下改動程式碼。

三、讓終端機認得 devpulse 指令

在 package.json 現有設定中加入 bin 欄位即可,不要整份覆蓋原本的檔案:

{
  "bin": {
    "devpulse": "./bin/devpulse.mjs"
  }
}

如果原本已經有 scripts、dependencies 等欄位,請保留它們,只把 bin 合併進去。接著在專案根目錄執行:

npm link

npm link 會把目前的本機套件連結成可在終端機呼叫的指令。完成後,可以先確認說明頁是否正常:

devpulse --help

再挑一個原始 Bug 範例來分析:

devpulse run samples/sql.cjs

若想先不設定 npm link,也可以直接使用 Node 執行入口檔:

node ./bin/devpulse.mjs run samples/sql.cjs

四、用顏色快速找到值得注意的問題

以 sql.cjs 為例,CLI 的輸出可能會像這樣(實際摘要與措辭會依 Gemini 的回應而變動):

DevPulse 程式碼審查
分析檔案:.../samples/sql.cjs

審查摘要
findUser 直接把輸入值拼進 SQL,可能造成 SQL Injection。

發現 1 個問題:

HIGH Line 3 [security] SQL 字串直接拼接使用者輸入
  原因:使用者輸入被直接組合進查詢字串。
  建議:改用 ? 佔位符,並把輸入值放進參數陣列。

這裡用紅色標示 high、黃色標示 medium、青色標示 low。顏色只是呈現方式,嚴重程度仍以 ReviewSchema 定義及 Flow 回傳的 severity 為準;不能因為終端機顯示紅色,就跳過人工確認。

如果看到「找不到檔案」,先確認指令中的相對路徑是以目前終端機所在目錄為基準;如果看到 API Key 或模型呼叫相關錯誤,則檢查 .env 是否存在、金鑰名稱是否與 Genkit 設定一致。CLI 的錯誤處理能把失敗訊息顯示出來,但不會自動修好環境設定。

今日學習踩坑小記

今天最大的收穫不是替終端機加上顏色,而是把已經完成的 AI Flow 包裝成真正順手的工具。CLI 負責接收指令、驗證輸入與呈現結果;codeReviewFlow 負責分析。把責任切清楚,之後才有空間增加自動修補、測試與報告輸出。

也要記住,CLI 印出「分析完成」只代表 Flow 有回傳結果,不代表程式碼沒有 Bug,更不代表修復通過測試。可靠的流程仍然要靠明確的測試條件驗收。

下一篇 Day 27,會讓 Antigravity 接手更多重複操作,嘗試把套用補丁與執行測試串成更自動化的工作流程。


Day 26 完成

  • ✅ 安裝 Chalk 與 dotenv
  • ✅ 建立 bin/devpulse.mjs,解析 run 指令與檔案路徑
  • ✅ 從 CLI 呼叫既有的 codeReviewFlow
  • ✅ 以顏色標示問題嚴重程度,並處理錯誤訊息
  • ✅ 透過 npm link 在終端機使用 devpulse run <filePath>

參考資料


上一篇
Day 25:紅綠燈驗證!看著單元測試從 Fail 到 Pass
下一篇
Day 27:代理人接手!讓 Antigravity 自動跑完「修補 → 驗收」流程
系列文
30 天玩轉 Google AI 全家桶:初學者的隨身 Coding 助理養成記 共 27 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言